//
//  MZ.swift
//  MZTool
//
//  Created by gby on 2022/1/25.
//

import Foundation


extension Double: MZNameSpace{}
extension CGSize: MZNameSpace {}
extension NSAttributedString: MZNameSpace {}
extension Date: MZNameSpace {}
extension DispatchQueue: MZNameSpace {}
extension CALayer: MZNameSpace {}
extension UIColor: MZNameSpace{}
extension UIImage: MZNameSpace{}
extension String: MZNameSpace{}
extension UIFont: MZNameSpace{}

extension UIView: MZNameSpace {
    public var mz: MZKit<UIView>{
        get {return MZKit(self)}
        set{}
    }
    public static var mz: MZKit<UIView>.Type {
        return MZKit<UIView>.self
    }
}

extension UIViewController: MZNameSpace {
    public var GBY: MZKit<UIViewController>{
        get {return MZKit(self)}
        set{}
    }
    public static var GBY: MZKit<UIViewController>.Type {
        return MZKit<UIViewController>.self
    }
}












typealias networkBegin = ()->Void
typealias networkFail = (_ error: Error?)->Void
typealias networkSuccess = (_ response: Any?)->Void
typealias networkFinal = (_ obj: Any?)->Void


public class MZ {
    
    public static func mainAsync(_ done: @escaping (() -> Void)) {
        if Thread.current.isMainThread {
            done()
        }else{
            let semaphore = DispatchSemaphore(value: 0)
            DispatchQueue.main.async {
                done()
                semaphore.signal()
            }
            semaphore.wait()
        }
    }
    
    //TODO:log打印
    public static func printLog<T>(_ message: T,file: String = #file, method: String = #function, line: Int = #line){
        #if DEBUG
        print("\((file as NSString).lastPathComponent)[\(line)], \(method): \(message)")
        #endif
    }
    
    
    
    public static func isSafeArea() -> Bool{
        if #available(iOS 11.0, *){
            return CGFloat(UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0.0) > 0.0
        }
        return false
    }
    
    public static func Navi_Height() -> CGFloat {
        if #available(iOS 11.0, *){
            return CGFloat(UIApplication.shared.windows.first?.safeAreaInsets.top ?? 0.0) + 44
        }
        return 64
    }
    public static func Navi_State_Height() -> CGFloat {
        if #available(iOS 11.0, *){
            return CGFloat(UIApplication.shared.windows.first?.safeAreaInsets.top ?? 20)
        }
        return 20

    }
    public static func Tabbar_Height() -> CGFloat {
        return MZ.isSafeArea() ? 49 + 34 : 49
    }
    
    
    
    //TODO:自定义颜色
    public static func RGB(_ red: CGFloat, _ green: CGFloat, _ blue: CGFloat, _ alpha: CGFloat) -> UIColor{
        return UIColor.init(red: red/255.0, green: green/255.0, blue: blue/255.0, alpha: alpha)
    }
    
    public static func RGB(_ color: String) -> UIColor{
        var cleanStr: String = color.replacingOccurrences(of: "#", with: "")
        if cleanStr.count == 3 {
            let inde1 = cleanStr.index(cleanStr.startIndex, offsetBy: 1)
            let inde2 = cleanStr.index(cleanStr.startIndex, offsetBy: 2)
            let inde3 = cleanStr.index(cleanStr.startIndex, offsetBy: 3)
            cleanStr = String(cleanStr[..<inde1]) + String(cleanStr[..<inde1]) + String(cleanStr[inde1..<inde2]) + String(cleanStr[inde1..<inde2]) + String(cleanStr[inde2..<inde3]) + String(cleanStr[inde2..<inde3])
        }
        if cleanStr.count == 6 {
            cleanStr += "ff"
        }
        var baseValue : UInt64 = 0
        Scanner.init(string: cleanStr).scanHexInt64(&baseValue)
        
        let red = CGFloat((baseValue >> 24) & 0xFF)/255.0
        let green = CGFloat((baseValue >> 16) & 0xFF)/255.0
        let blue = CGFloat((baseValue >> 8) & 0xFF)/255.0
        let alpha = CGFloat((baseValue >> 0) & 0xFF)/255.0
        
        return UIColor.init(red: red, green: green, blue: blue, alpha: alpha)
    }
    
    
    //TODO:自定义图片方法
    public static func IMG(_ named: String) -> UIImage?{
        return UIImage.init(named: named)
    }
    
    public static func IMG(bundleName: String, named: String) -> UIImage?{
        let filePath = Bundle.main.path(forResource: bundleName, ofType: "bundle")
        let targetbundle = Bundle.init(path: filePath ?? "")
        var image: UIImage?
        var sufix = "@2x"
        if UIScreen.main.scale > 2 {
            sufix = "@3x"
        }
        if #available(iOS 13.0, *) {
            image = UIImage.init(named: named + sufix, in: targetbundle, with: nil)
        } else {
            image = UIImage.init(contentsOfFile: targetbundle?.path(forResource: named + sufix, ofType: "png") ?? "")
        }
        if image == nil {
            return UIImage.init(named: named)
        }
        return image
    }

    //TODO:获取刘海
    public static func windowSafeAreaInsets() -> UIEdgeInsets {
        guard #available(iOS 11.0, *), let safeAreaInsets = UIApplication.shared.delegate?.window??.safeAreaInsets else {
            return UIEdgeInsets.zero
        }
        return safeAreaInsets
    }


    //TODO:判断当前视图是否在展示状态
    public static func viewInWindowShow(view: UIView) -> Bool{
        var keywindow: UIWindow?
        if #available(iOS 13, *) {
            keywindow = UIApplication.shared.windows.first { $0.isKeyWindow }
        } else {
            keywindow = UIApplication.shared.keyWindow
        }
        guard let window = keywindow else {
            return false
        }
        let newFrame = window.convert(view.frame, from: view.superview)
        let winBounds = window.bounds
        let intersects = newFrame.intersects(winBounds)
        return (!view.isHidden && view.alpha > 0.01 && view.window == keywindow && intersects)
    }


    //TODO:获取某个视图快照
    public static func viewToImg(view: UIView) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(view.frame.size, false, 3.0)
        defer {
            UIGraphicsEndImageContext()
        }
        guard let ctx = UIGraphicsGetCurrentContext() else {
            return nil
        }
        view.layer.render(in: ctx)
        let img = UIGraphicsGetImageFromCurrentImageContext()
        return img
    }
    
    //TODO:方法替换
    public static func swizzlingForClass(_ cls: AnyClass?,_ originSelector: Selector,_ swizzleSelector: Selector) {
        let originMethod = class_getInstanceMethod(cls, originSelector)
        let swizzleMethod = class_getInstanceMethod(cls, swizzleSelector)
        guard let swMethod = swizzleMethod, let oMethod = originMethod else { return }
        let didAddSuccess: Bool = class_addMethod(cls, originSelector, method_getImplementation(swMethod), method_getTypeEncoding(swMethod))
        if didAddSuccess {
            class_replaceMethod(cls, swizzleSelector, method_getImplementation(oMethod), method_getTypeEncoding(oMethod))
        } else {
            method_exchangeImplementations(oMethod, swMethod)
        }
    }
    
    //TODO: 打电话
    public static func makePhone(_ phone: String?){
        guard let p = phone else {
            return
        }
        let pphone = "telprompt://" + p
        if UIApplication.shared.canOpenURL(URL(string: pphone)!) {
            UIApplication.shared.open(URL(string: pphone)!)
        }
    }
    
    //TODO: 复制
    public static func pasteboardStore(_ str: String?) -> Bool{
        guard let s = str else {
            return false
        }
        let past = UIPasteboard.general
        past.string = s
        return true
    }
    //TODO: 属性列表: 通过ivar
    public static func gainIvarNames(objc: AnyClass, isPrint: Bool = false) -> [String] {
        var count1: UInt32 = 0
        let ivas = class_copyIvarList(objc, &count1)
        var ivarNameList: [String] = []
        for i  in 0..<count1 {
            let ivar = ivas![Int(i)]
            let key = String(cString: ivar_getName(ivar)!)
#if DEBUG
                if isPrint {print(key)}
#endif
            ivarNameList.append(key)
        }
        free(ivas)
        return ivarNameList
    }
    //TODO: 属性列表: 通过propert
    public static func gainPropertyNames(objc: AnyClass, isPrint: Bool = false) -> [String] {
        var count1: UInt32 = 0
        let propertys = class_copyPropertyList(objc, &count1)
        var propertyNameList: [String] = []
        for i  in 0..<count1 {
            let ivar = propertys![Int(i)]
            let key = String(cString: property_getName(ivar))
#if DEBUG
                if isPrint {print(key)}
#endif
            propertyNameList.append(key)
        }
        free(propertys)
        return propertyNameList
    }
    //TODO: 方法列表
    public static func gainMethodNames(objc: AnyClass, isPrint: Bool = false) -> [Any] {
        var count1: UInt32 = 0
        let methods = class_copyMethodList(objc, &count1)
        var methodNameList: [Any] = []
        for i  in 0..<count1 {
            let method = methods![Int(i)]
            let methodName = method_getName(method)
//            let methodName = sel_getName(sel)
            methodNameList.append(methodName)
        }
        free(methods)
        return methodNameList
    }
}





extension MZ{
    
    public static func windowRootVCNavi() -> UINavigationController? {
        var keywindow: UIWindow?
        if #available(iOS 13, *) {
            keywindow = UIApplication.shared.windows.first { $0.isKeyWindow }
        } else {
            keywindow = UIApplication.shared.keyWindow
        }
        
        if let rvc = keywindow?.rootViewController, rvc.isKind(of: UINavigationController.self), let navi = rvc as? UINavigationController {
            return navi
        }
        if let rvc = keywindow?.rootViewController as? UITabBarController, let navi =  rvc.selectedViewController as? UINavigationController {
            return navi
        }
        return nil
    }
    
}
